`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: Wuhan University
// Engineer: Yu Zihao
// 
// Create Date: 2021/08/15 10:52:50
// Design Name: 
// Module Name: cpu
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
//
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module cpu(clk,reset,N,V,Z,
           mem_addr,mem_cmd,read_data,write_data);
input clk, reset; 
input [15:0] read_data;
output [15:0] write_data;
output [8:0] mem_addr;
output [1:0] mem_cmd;//mem read or writ: MNONE,MREAD,MWRITE
output N, V, Z;

`define MNONE  2'00
`define MREAD  2'01
`define MWRITE 2'10

wire [15:0] datapath_out;

wire addr_sel; //1:pc; 0:STR LDR struction
//Program Counter
wire firstPC = 9'b0;
wire reset_pc, load_pc;
wire [8:0] next_pc, pc;
assign next_pc = reset_pc ? firstPC : pc+9'b1;
VDFFE #(.n(9)) pcCounter(.clk(clk), .in(next_pc), .load(load_pc), .out(pc), .rst(reset));

//STR LDR struction
wire [8:0] data_addr_out;
wire load_addr;
assign mem_addr = addr_sel ? pc : data_addr_out;
VDFFE #(.n(9)) dataAddress(.clk(clk), .in(datapath_out[8:0]), .load(load_addr), .out(data_addr_out), .rst(reset));

//instruction register
wire [15:0] ins;
wire load_ir;
VDFFE insReg(.clk(clk), .in(read_data), .load(load_ir), .out(ins), .rst(reset));

//instruction decoder
wire [2:0] opcode, Rn, Rd, Rm, nsel;//nsel use one-hot
wire [1:0] op, shift, ALUop;

wire [15:0] sximm5, sximm8;
wire [2:0] readnum, writenum;

assign opcode = ins[15:13];
assign op = ins[12:11];
assign Rn = ins[10:8];
assign Rd = ins[7:5];
assign Rm = ins[2:0];
assign shift = ins[4:3];
assign sximm8 = {{8{ins[7]}},ins[7:0]};
assign sximm5 = {{11{ins[4]}},ins[4:0]};
assign ALUop = ins[12:11];

//read write num MUX with one-hot
//nsel = 001 Rm
//nsel = 010 Rd
//nsel = 100 Rn
assign readnum = writenum;
assign writenum = ({3{nsel[0]}}&Rm) | ({3{nsel[1]}}&Rd) | ({3{nsel[2]}}&Rn);

//state machine
//input
//input clk, reset, s;
//wire [2:0] opcode;wire [1:0] op;
//output
//wire [2:0] nsel;
wire write, asel, bsel, loada, loadb, loadc, loads;
wire [1:0] vsel;
CPUSTM cpustm(.clk(clk),.reset(reset),.opcode(opcode),.op(op),
              .load_addr(load_addr),.load_ir(load_ir),.load_pc(load_pc),.addr_sel(addr_sel),.mem_cmd(mem_cmd),.reset_pc(reset_pc),
              .nsel(nsel),.write(write),.vsel(vsel),.asel(asel),
              .bsel(bsel),.loada(loada),.loadb(loadb),.loadc(loadc),.loads(loads));
//data path
datapath datapath_inst(.writenum(writenum), .write(write), 
                       .readnum(readnum), .clk(clk), .reset(reset), .vsel(vsel), .asel(asel), .bsel(bsel),
                       .shift(shift), .ALUop(ALUop), .loada(loada), .loadb(loadb), 
                       .loadc(loadc), .loads(loads), .sximm5(sximm5), .sximm8(sximm8), .mdata(read_data),
                       .datapath_out(datapath_out), .data_out(write_data), .N_out(N), .V_out(V), .Z_out(Z));
                       

endmodule

